﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace Sakura.Media.AviSynth.Native
{
	/// <summary>
	/// 表示一个视频的信息。
	/// </summary>
	[StructLayout(LayoutKind.Sequential)]
	internal struct AvsVideoInfo
	{
		/// <summary>
		/// 视频的宽度，以像素为单位。如果该字段为 <c>0</c>，则表示没有视频内容。
		/// </summary>
		public int Width;
		/// <summary>
		/// 视频的高度，以像素为单位。
		/// </summary>
		public int Height;
		/// <summary>
		/// 帧刷新速率的分子。
		/// </summary>
		public int FpsNumerator;
		/// <summary>
		/// 帧刷新速率的分母。
		/// </summary>
		public int FpsDenominator;
		/// <summary>
		/// 帧数目。
		/// </summary>
		public int NumberOfFrames;
		/// <summary>
		/// 像素类型。
		/// </summary>
		public PixelFormat PixelType;
		/// <summary>
		/// 每秒钟的音频样本个数。如果该字段为 <c>0</c>，则表示没有音频内容。
		/// </summary>
		public int AudioSamplesPerSecond;
		/// <summary>
		/// 音频的采样类型。
		/// </summary>
		public SampleType SampleType;
		/// <summary>
		/// 音频的采样数。
		/// </summary>
		public long NumberOfAudioSamples;
		/// <summary>
		/// 音频的通道数。
		/// </summary>
		public int Channels;
		/// <summary>
		/// 图像的类型。
		/// </summary>
		public ImageType ImageType;

		#region 辅助方法

		/// <summary>
		/// 获取一个值，指示该视频信息是否包含视频。
		/// </summary>
		public bool HasVideo
		{
			get
			{
				return this.Width != 0;
			}
		}

		/// <summary>
		/// 获取一个值，指示该视频信息是否包含音频。
		/// </summary>
		public bool HasAudio
		{
			get
			{
				return this.AudioSamplesPerSecond != 0;
			}
		}

		/// <summary>
		/// 获取视频每个像素占用的位数。
		/// </summary>
		public int BitsPerPixel
		{
			get
			{
				switch (this.PixelType)
				{
					case PixelFormat.Bgr24:
						return 24;
					case PixelFormat.Bgr32:
						return 32;
					case PixelFormat.Yuv2:
						return 16;
					case PixelFormat.I420:
						return 12;
					default:
						return 0;
				}
			}
		}

		/// <summary>
		/// 获取指定个数的像素在当前视频格式下需要占用的字节数。
		/// </summary>
		/// <param name="pixelCount">要计算的像素格式。</param>
		/// <returns>指定像素个数下占用的总字节数。</returns>
		/// <remarks>注意，对于 YUV 格式，此方法不能获得准确结果。</remarks>
		public int BytesFromPixels(int pixelCount)
		{
			return pixelCount * (this.BitsPerPixel >> 3);
		}

		/// <summary>
		/// 获取视频单行需要占据的字节数。
		/// </summary>
		public int RowSize
		{
			get
			{
				return this.BytesFromPixels(this.Width);
			}
		}

		/// <summary>
		/// 获取单个位图占据的总字节数。
		/// </summary>
		public int BitmapSize
		{
			get
			{
				if (this.PixelType.HasFlag(PixelFormat.Plannar))
				{
					var p = this.Height * ((this.RowSize + 3) & ~3);
					p += p >> 1;

					return p;
				}
				else
				{
					var p = this.Height * ((this.RowSize + 3) & ~3);
					p += p >> 1;

					return p;
				}
			}
		}

		/// <summary>
		/// 获取音频每个通道单个样本占据的字节数。
		/// </summary>
		public int BytesPerChannelSample
		{
			get
			{
				switch (this.SampleType)
				{
					case SampleType.Int8:
						return 1;
					case SampleType.Int16:
						return 2;
					case SampleType.Int24:
						return 3;
					case SampleType.Int32:
						return 4;
					case SampleType.Float:
						return 8;
					default:
						return 0;
				}
			}
		}

		/// <summary>
		/// 获取音频每个样本占据的总字节数。
		/// </summary>
		public int BytesPerSample
		{
			get
			{
				return this.BytesPerSample * this.Channels;
			}
		}

		/// <summary>
		/// 获取指定帧数需要的音频样本总数。
		/// </summary>
		/// <param name="frameCount">要计算的帧数。</param>
		/// <returns>指定帧数下的样本总数。</returns>
		public long AudioSamplesFromFrames(long frameCount)
		{
			return frameCount * this.AudioSamplesPerSecond * this.FpsDenominator / this.FpsNumerator;
		}

		/// <summary>
		/// 获取指定音频样本数需要的帧总数。
		/// </summary>
		/// <param name="frameCount">要计算的音频样本数。</param>
		/// <returns>指定样本数下的帧总数。</returns>
		public long FramesFromAudioSamples(long sampleCount)
		{
			return sampleCount * this.FpsNumerator / this.FpsDenominator / this.AudioSamplesPerSecond;
		}

		/// <summary>
		/// 获取指定字节数包含的音频样本总数。
		/// </summary>
		/// <param name="frameCount">要计算的字节帧数。</param>
		/// <returns>指定字节数下的样本总数。</returns>
		public long AudioSamplesFromBytes(long byteCount)
		{
			return byteCount / this.BytesPerSample;
		}

		/// <summary>
		/// 获取指定音频样本数需要的总字节数。
		/// </summary>
		/// <param name="frameCount">要计算的音频样本数。</param>
		/// <returns>指定样本数下的总字节数。</returns>
		public long BytesFromAudioSamples(long sampleCount)
		{
			return sampleCount * this.BytesPerSample;
		}

		#endregion
	}
}
